package soo.service;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.log4j.Logger;

public class Fubao {

    // 218.108.162.121已经被封闭

    static Logger log = Logger.getLogger(Fubao.class.getName());

    private HttpClient client;

    public static String TOP_DIR = "guahaolog";

    public static String LOGIN_CODE_URL = TOP_DIR + "/loginCode.jpeg";

    private String selvalParam;

    private int formCheckCodeNum = 0;

    private String docUrl;

    boolean isAsc = false;

    // urlDoctorMap.put("普通产科",
    // "http://guahao.zjol.com.cn/DepartMent.Aspx?ID=3271");

    public Fubao(String docUrl) {
        super();
        client = new HttpClient();
        client.getHttpConnectionManager().getParams().setConnectionTimeout(1000 * 10000);
        // 设置读数据超时时间
        client.getHttpConnectionManager().getParams().setSoTimeout(1000 * 10000);
        // 获取连接的时间
        client.getParams().setConnectionManagerTimeout(1000 * 10000);

        selvalParam = this.getSelvalParamName();
        this.docUrl = docUrl;
        // x-forward-for:202.204.76.254

    }

    public void doGetLoginVerifyCodeImg() {
        log.error("获取验证码信息,存储地址：" + LOGIN_CODE_URL);
        GetMethod getFirst = new GetMethod("http://guahao.zjol.com.cn/VerifyCodeCH.aspx");
        getFirst.setRequestHeader("Referer", docUrl);

        this.requestInterceptor(getFirst);
        try {
            int status = client.executeMethod(getFirst);

            InputStream inputstream = getFirst.getResponseBodyAsStream();
            BufferedInputStream bis = new BufferedInputStream(inputstream);
            FileOutputStream fos = new FileOutputStream(LOGIN_CODE_URL);
            BufferedOutputStream bos = new BufferedOutputStream(fos);
            int read;
            while ((read = bis.read()) != -1) {
                bos.write(read);
            }
            bos.close();// 不关闭，输出流不刷新，有可能得到无效图片 o

            client.getState().addCookies(client.getState().getCookies());

        } catch (Exception e) {
            log.error(e);
        } finally {
            getFirst.releaseConnection();
        }
        log.error("图片已经存储");
        return;
    }

    /**
     * 
     * @param client
     * @param userName
     * @param pwd
     * @return
     */
    public String doLogin(String userName, String pwd, String verifyCode) {
        String result = "";
        int maxtry = 5;
        while (result.indexOf("OK") < 0) {
            if (maxtry-- < 0) {
                return "error" + result;
            }

            String url = "http://guahao.zjol.com.cn/ashx/LoginDefault.ashx?idcode=" + userName + "&pwd=" + pwd
                    + "&txtVerifyCode=" + verifyCode;

            GetMethod getMethod2 = new GetMethod(url);
            this.requestInterceptor(getMethod2);

            try {

                // 开始进行登录验证信息提交， 关键是注意参数的顺序
                if (HttpStatus.SC_OK == client.executeMethod(getMethod2)) {

                    client.getState().addCookies(client.getState().getCookies());
                    result = getResponseBody(getMethod2.getResponseBodyAsStream(), "UTF-8");
                    log.error("login info" + result);
                    System.out.print("login info" + result);
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                getMethod2.releaseConnection();
            }
        }
        GetMethod getMethodIndex = new GetMethod("http://guahao.zjol.com.cn");
        try {
            this.requestInterceptor(getMethodIndex);
            if (HttpStatus.SC_OK == client.executeMethod(getMethodIndex)) {

                client.getState().addCookies(client.getState().getCookies());
                String index = getResponseBody(getMethodIndex.getResponseBodyAsStream(), "UTF-8");
                int start = index.indexOf("欢迎您");
                System.out.println("login user:" + index.substring(start, start + 8));
                log.error("login user" + index.substring(start, start + 8));
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            getMethodIndex.releaseConnection();
        }

        return result;
    }

    public boolean doBookTicket(long bookTimeInMillis) {
        String code = this.getDoctorCodeInfo(docUrl, bookTimeInMillis);
        List<Map<String, String>> paramMapList = this.generateBookForm(code);

        return this.submitBookForm(paramMapList);

    }

    /**
     * 获取预订的医生的信息。 注意由于是在下午3点放票。所以。。。
     * 
     * @param client
     * @param doctorUrl
     * @return
     */
    private String getDoctorCodeInfo(String doctorUrl, long bookTimeInMillis) {
        int oneSecond = 1000;

        String code = "";
        int dd = 0;
        getSubmitFormCheckCode();
        System.out.println("begin get doc code info:" + doctorUrl);

        while (dd++ < 2000) {
            GetMethod getFirst = new GetMethod(doctorUrl);
            this.requestInterceptor(getFirst);
            try {
                log.error("第" + dd + "次，尝试获取医生票源信息。");
                long nowTimeInMillis = Calendar.getInstance().getTimeInMillis();
                // 间隔的分钟
                int jianGeInMin = (int) (bookTimeInMillis - nowTimeInMillis) / (1000 * 60);
                if (dd > 6) {
                    if (jianGeInMin < 1) {
                        if (jianGeInMin > -3) {
                            // 到前一分钟开始暴力尝试
                        } else if (jianGeInMin > -10) {
                            Thread.sleep(oneSecond * 2);
                        } else {
                            // break;// 订票时间过了10分钟后，退出。
                            Thread.sleep(oneSecond * 20);
                            break;
                        }
                    } else if (jianGeInMin < 3) {
                        Thread.sleep(oneSecond * 2);
                        dd = 5;
                    } else if (jianGeInMin < 10) {
                        getSubmitFormCheckCode();
                        Thread.sleep(oneSecond * 20);
                        dd = 5;
                    } else {
                        Thread.sleep(oneSecond * 60);
                        dd = 5;
                    }
                }
                client.executeMethod(getFirst);

                String result = getResponseBody(getFirst.getResponseBodyAsStream(), "UTF-8");

                String codeBeginStr = "javascript:showDiv('";
                int codeStart = result.indexOf(codeBeginStr);
                if (codeStart > 0) {

                    int codeEnd = result.indexOf("'", codeStart + codeBeginStr.length());
                    code = result.substring(codeStart + codeBeginStr.length(), codeEnd);
                    log.error("票源信息获取成功，下面开始尝试订票!" + code);
                    return code;
                    // Parser parser = new Parser(result);
                    // parser.setInputHTML(result);
                    // NodeFilter tableFilter = new
                    // NodeClassFilter(TableTag.class);
                    // NodeList tableList =
                    // parser.extractAllNodesThatMatch(tableFilter);
                    //
                    // for (int i = 0; i < tableList.size(); i++) {
                    // TableTag table = (TableTag) tableList.elementAt(i);
                    // // 取得表中的行集
                    // TableRow[] rows = table.getRows();
                    // // 遍历每行
                    // for (int r = 0; r < rows.length; r++) {
                    // TableRow tr = rows[r];
                    // TableColumn[] td = tr.getColumns();
                    // // 行中的列
                    // for (int c = 0; c < td.length; c++) {
                    // String str = td[c].toHtml();
                    // String[] ss = str.split("'");
                    // if (ss.length > 2) {
                    // for (int pp = 0; pp < ss.length - 1; pp++) {
                    // if (ss[pp].indexOf("javascript:showDiv") >= 0) {
                    // code = ss[pp + 1];
                    // log.error("票源信息获取成功，下面开始尝试订票!" + code);
                    // return code; // FIXME jeffry
                    // }
                    // }
                    // }
                    // }
                    // }
                    // }
                } else if (dd == 1) {
                    int docnameStart = result.indexOf("医生姓名");
                    if (docnameStart >= 0) {
                        String docName = result.substring(docnameStart, docnameStart + 12);
                        System.out.println(docName);
                        log.error(docName);
                    }
                }
            } catch (Exception e) {
                log.error(e);
            } finally {
                getFirst.releaseConnection();
            }

        }
        return code;
    }

    private List<Map<String, String>> generateBookForm(String code) {
        String url = "http://guahao.zjol.com.cn/ashx/gethy.ashx";
        PostMethod method = new PostMethod(url);
        method.setRequestHeader("Referer", docUrl);

        this.requestInterceptor(method);
        method.addParameter("sg", code);
        List<Map<String, String>> listMap = new ArrayList<Map<String, String>>();

        try {
            if (HttpStatus.SC_OK == client.executeMethod(method)) {
                String piaosAndCode = getResponseBody(method.getResponseBodyAsStream(), "UTF-8");
                int begin = piaosAndCode.lastIndexOf("#$");
                if (begin > 0) {
                    // #$18649205|5|0840$18649207|7|0856$18649208|8|0904$
                    // 注意： fxw2o17是一个动态的参数,对应方法getSelvalParamName（）
                    // 格式说名： {fxw2o17|{xh}|{qhsj}|
                    piaosAndCode = piaosAndCode.substring(begin + 2, piaosAndCode.length());
                    log.error("total piao:" + piaosAndCode);

                    String[] tt = piaosAndCode.split("#");
                    if (tt.length == 2) {
                        String[] piaos = tt[0].split("\\$");
                        if (piaos.length > 0) {
                            for (int i = 0; i < piaos.length; i++) {
                                String[] piao = piaos[i].split("\\|");
                                if (piao.length == 3) {
                                    Map<String, String> paramMap = new HashMap<String, String>();
                                    paramMap.put(selvalParam, piao[0]);
                                    paramMap.put("xh", piao[1]);
                                    paramMap.put("qhsj", piao[2]);
                                    paramMap.put("sg", tt[1]);
                                    paramMap.put("yzm", "" + formCheckCodeNum);// 数字加的验证码。
                                    if (isAsc) {
                                        listMap.add(paramMap);
                                    } else {
                                        listMap.add(0, paramMap);

                                    }
                                }
                            }
                        }
                    }

                }
            }
        } catch (Exception e) {
            log.error(e);
        } finally {
            method.releaseConnection();
        }
        return listMap;
    }

    public String getSelvalParamName() {
        String url = "http://guahao.zjol.com.cn/js/dialogB.js";
        String result = "";
        GetMethod method = new GetMethod(url);
        this.requestInterceptor(method);
        try {
            if (HttpStatus.SC_OK == client.executeMethod(method)) {
                String js = getResponseBody(method.getResponseBodyAsStream(), "UTF-8");
                // 下面这是js的格式，我们需要取到 fxw2o17；
                // function zYuyue(){ var fxw2o17 =
                // document.getElementById("selval");var
                int start = js.indexOf("var") + 3;
                int end = js.indexOf("=");
                result = js.substring(start, end).trim();

            }
        } catch (Exception e) {
            log.error(e);
        } finally {
            method.releaseConnection();
        }
        return result;
    }

    public boolean submitBookForm(List<Map<String, String>> listMap) {
        String url = "http://guahao.zjol.com.cn/ashx/TreadYuyue.ashx";
        if (listMap.size() < 1) {
            return false;
        }

        for (Map<String, String> paramMap : listMap) {
            String str = doSubmitBook(url, paramMap);

            if (str.length() > 50) {
                log.error("订票成功返回信息：" + str);
                System.out.println(str);
                return true;
            } else {
                log.error("定票失败：" + str);
            }

        }
        return false;

    }

    /**
     * @param url
     * @param paramMap
     * @param tryNum
     */
    protected String doSubmitBook(String url, Map<String, String> paramMap) {

        PostMethod method = new PostMethod(url);
        this.requestInterceptor(method);
        for (Map.Entry<String, String> entry : paramMap.entrySet()) {
            method.addParameter(entry.getKey(), entry.getValue());
        }
        String str = "";
        try {
            if (HttpStatus.SC_OK == client.executeMethod(method)) {
                str = getResponseBody(method.getResponseBodyAsStream(), "UTF-8");

            } else {
                String result = getResponseBody(method.getResponseBodyAsStream(), "UTF-8");
                log.error("订票失败信息：" + result);
            }
        } catch (Exception e) {
            log.error(e);
        } finally {
            method.releaseConnection();
        }
        return str;
    }

    /**
     * @param client
     */
    private void getSubmitFormCheckCode() {
        GetMethod getFirst = new GetMethod("http://guahao.zjol.com.cn/VerifyCodeCH_SG.aspx");
        getFirst.setRequestHeader("Referer", "http://guahao.zjol.com.cn/DepartMent.Aspx?ID=44&T=T");

        this.requestInterceptor(getFirst);
        try {
            if (HttpStatus.SC_OK == client.executeMethod(getFirst)) {
                InputStream inputstream = getFirst.getResponseBodyAsStream();
                BufferedInputStream bis = new BufferedInputStream(inputstream);
                FileOutputStream fos = new FileOutputStream(TOP_DIR + "/formCode.jpeg");
                BufferedOutputStream bos = new BufferedOutputStream(fos);
                int read;
                while ((read = bis.read()) != -1) {
                    bos.write(read);
                }
                bos.close();// 不关闭，输出流不刷新，有可能得到无效图片 o

                client.getState().addCookies(client.getState().getCookies());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                getFirst.releaseConnection();
            } catch (Exception e) {

            }
            formCheckCodeNum = FormVerCodeParser.getFubaoImgCode(TOP_DIR + "/formCode.jpeg");

        }

    }

    private void requestInterceptor(HttpMethod method) {
        method.setRequestHeader("User-Agent",
                "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; BOIE9;ZHCN)");

        method.setRequestHeader("Connection", "Keep-Alive");// close
        method.setRequestHeader("Cache-Control", "no-cache");
        method.setRequestHeader("Accept_Encoding", "gzip, deflate");

    }

    private String getResponseBody(InputStream inputStream, String encode) throws IOException {
        int max_bytes = 4096;
        byte[] b = new byte[max_bytes];
        StringBuilder builder = new StringBuilder();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int bytesRead = inputStream.read(b, 0, max_bytes);
        while (bytesRead != -1) {
            baos.write(b, 0, bytesRead);
            builder.append(new String(b, 0, bytesRead));
            bytesRead = inputStream.read(b, 0, max_bytes);
        }
        String content = baos.toString(encode);
        baos.close();
        return content;
    }

    public static void main(String[] args) {
        String str = "javascript:showDiv('3B5DFD34CD0C420D87FD8B013EF20311E429028674716AFB7FE034A4237963BE39814198319B7A5A7F080A7FCFA0A9B9D11E4188E8B851EFC7114CB4206A148EB62F2B6F0D1A25EF')";
        str.indexOf("javascript:showDiv('");
    }
}
